package com.sqx.modules.health.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sqx.common.utils.RedisUtils;
import com.sqx.modules.health.common.Constants;
import com.sqx.modules.health.common.Result;
import com.sqx.modules.health.entity.Files;
import com.sqx.modules.health.service.IFilesService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;

/**
 * <p>
 * 上传文件 前端控制器
 * </p>
 *
 * @author xglhappy
 * @since 2022-04-14
 */

@Api(value = "上传文件", tags = "", description = "")
@RestController
@RequestMapping("/health/files")
public class FilesController {

    @Value("${files.upload.path}")
    private String fileUploadPath;

    @Value("${server.ip}")
    private String serverIp;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private IFilesService filesService;

    // 新增或更新
    @PostMapping("/save")
    @ApiOperation(value = "新增或更新上传文件", notes = "新增或更新上传文件")
    public Result save(@RequestBody Files files) {
        return Result.success(filesService.saveOrUpdate(files));
    }

    // 根据ID删除
    @GetMapping("/del/{id}")
    @ApiOperation(value = "根据ID删除上传文件", notes = "根据ID删除上传文件")
    public Result delete(@PathVariable Integer id) {
        return Result.success(filesService.removeById(id));
    }

    @GetMapping("/delByFileName")
    @ApiOperation("根据文件名称删除文件")
    public Result delByFileName(@RequestParam String fileName) {
        Boolean result = false;
        try {
            QueryWrapper<Files> wrapper = new QueryWrapper<>();
            wrapper.eq("url", fileName);
            Files file = filesService.getOne(wrapper);
            if (file == null) {
                return Result.error(Constants.CODE_500,"error");
            }
            if (filesService.removeById(file.getId())) {
                result = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.success(result);
    }

    // 根据IDS删除
    @PostMapping("/del/batch")
    @ApiOperation(value = "根据IDS删除上传文件", notes = "根据IDS删除上传文件")
    public Result deleteBatch(@RequestBody List<Integer> ids) {
        return Result.success(filesService.removeByIds(ids));
    }

    // 查询全部
    @GetMapping("/findAll")
    @ApiOperation(value = "查询全部上传文件", notes = "查询全部上传文件")
    public Result findAll() {
        return Result.success(filesService.list());
    }

    // 根据ID查询一条记录
    @GetMapping("/findOne")
    @ApiOperation(value = "根据ID查询一条记录上传文件", notes = "根据ID查询一条记录上传文件")
    public Result findOne(@RequestParam Integer id) {
        return Result.success(filesService.getById(id));
    }

    // 分页查询
    @GetMapping("/findPage")
    @ApiOperation(value = "分页查询上传文件", notes = "分页查询上传文件")
    public Result findPage(@RequestParam Integer pageNum, @RequestParam Integer pageSize) {
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");
        return Result.success(filesService.page(new Page<>(pageNum, pageSize), queryWrapper));
    }

    /**
     * 文件上传接口
     *
     * @param file 前端传递过来的文件
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public String upload(MultipartFile file, HttpServletRequest request) throws IOException {

        String originalFilename = file.getOriginalFilename();
        String type = FileUtil.extName(originalFilename);
        long size = file.getSize();

        // 定义一个文件唯一的标识码
        String fileUUID = IdUtil.fastSimpleUUID() + StrUtil.DOT + type;

        File uploadFile = new File(fileUploadPath + "/" + fileUUID);
        // 判断配置的文件目录是否存在，若不存在则创建一个新的文件目录
        File parentFile = uploadFile.getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }

        String url;
        // 获取文件的md5
        String md5 = SecureUtil.md5(file.getInputStream());
        // 从数据库查询是否存在相同的记录
        Files dbFiles = getFileByMd5(md5);
        if (dbFiles != null) {
            url = dbFiles.getUrl();
        } else {
            // 上传文件到磁盘
            file.transferTo(uploadFile);
            // 数据库若不存在重复文件，则不删除刚才上传的文件
            url = "/uploads/" + fileUUID;
        }

        // 存储数据库
        Files saveFile = new Files();
        saveFile.setName(originalFilename);
        saveFile.setType(type);
        saveFile.setSize(size / 1024); // 单位 kb
        saveFile.setUrl(url);
        saveFile.setMd5(md5);
        filesService.save(saveFile);
//        url = "http://" + serverIp + ":9090/uploads/" + fileUUID;
        url = "/uploads/" + fileUUID;
        // 从redis取出数据，操作完，再设置（不用查询数据库）
//        String json = redisUtils.get(Constants.FILES_KEY);
//        List<Files> files1 = JSONUtil.toBean(json, new TypeReference<List<Files>>() {
//        }, true);
//        files1.add(saveFile);
//        setCache(Constants.FILES_KEY, JSONUtil.toJsonStr(files1));
        // 从数据库查出数据
//        List<Files> files = fileMapper.selectList(null);
//        // 设置最新的缓存
//        setCache(Constants.FILES_KEY, JSONUtil.toJsonStr(files));
        // 最简单的方式：直接清空缓存
//        flushRedis(Constants.FILES_KEY);

        return url;
    }

    /**
     * 文件下载接口   http://localhost:9090/file/{fileUUID}
     *
     * @param fileUUID
     * @param response
     * @throws IOException
     */
    @GetMapping("/download/{fileUUID}")
    public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {
        // 根据文件的唯一标识码获取文件
        File uploadFile = new File(fileUploadPath + "/" + fileUUID);
        // 设置输出流的格式
        ServletOutputStream os = response.getOutputStream();
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8"));
        response.setContentType("application/octet-stream");
        // 读取文件的字节流
        os.write(FileUtil.readBytes(uploadFile));
        os.flush();
        os.close();
    }

    @GetMapping("/downloadLocal")
    public void downloadLocal(String fileUUID, HttpServletResponse response) throws FileNotFoundException {
        // 下载本地文件
        String fileName = fileUploadPath + "/" + fileUUID; // 文件的默认保存名
        // 根据文件的唯一标识码获取文件
//        File uploadFile = new File(fileUploadPath + "/" + fileUUID);
        // 读到流中
        InputStream inStream = new FileInputStream(fileName);// 文件的存放路径
        // 设置输出的格式
        response.reset();
        response.setContentType("text/plain;charset=UTF-8");
        response.addHeader("Content-Disposition", "attachment; filename=\"" + fileUUID);
        // 循环取出流中的数据
        byte[] b = new byte[100];
        int len;
        try {
            while ((len = inStream.read(b)) > 0)
                response.getOutputStream().write(b, 0, len);
            inStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过文件的md5查询文件
     *
     * @param md5
     * @return
     */
    private Files getFileByMd5(String md5) {
        // 查询文件的md5是否存在
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5", md5);
        List<Files> filesList = filesService.list(queryWrapper);
        return filesList.size() == 0 ? null : filesList.get(0);
    }

    // 删除缓存
    private void flushRedis(String key) {
        redisUtils.delete(key);
    }
}

